#pragma once
#include "ParticleData.h"
#include "NeighborhoodSearchSpatialHashing.h"
namespace Simulation {
	class FluidModel
	{
	public:
		FluidModel();
		virtual ~FluidModel();

	protected:
		double viscosity;
		double m_density0;
		double m_particleRadius;
		double m_supportRadius;
		ParticleData m_particles;
		std::vector<glm::dvec3> m_boundaryX;
		std::vector<double> m_boundaryPsi;
		std::vector<double> m_density;
		std::vector<double> m_lambda;
		std::vector<glm::dvec3> m_deltaX;
		NeighborhoodSearchSpatialHashing* m_neighborhoodSearch;

		void initMasses();

		void resizeFluidParticles(const unsigned int newSize);
		void releaseFluidParticles();
	public:
		void cleanupModel();
		virtual void reset();

		ParticleData& getParticles();

		void initModel(const unsigned int nFluidParticles,
			glm::dvec3* fluidParticles, 
			const unsigned int nBoundaryParticles,
			glm::dvec3* boundaryParticles);

		const unsigned int numBoundaryParticles() const { return (unsigned int)m_boundaryX.size(); }
		double getDensity0() const { return m_density0; }
		double getSupportRadius() const { return m_supportRadius; }
		double getParticleRadius() const { return m_particleRadius; }
		void setParticleRadius(double val) { 
			m_particleRadius = val; 
			m_supportRadius = static_cast<double>(4.0) * m_particleRadius; 
		}
		NeighborhoodSearchSpatialHashing* getNeighborhoodSearch() { return m_neighborhoodSearch; }

		double getViscosity() const { return viscosity; }
		void setViscosity(double val) { viscosity = val; }

		FORCE_INLINE const glm::dvec3& getBoundaryX(const unsigned int i) const
		{
			return m_boundaryX[i];
		}

		FORCE_INLINE glm::dvec3& getBoundaryX(const unsigned int i)
		{
			return m_boundaryX[i];
		}

		FORCE_INLINE void setBoundaryX(const unsigned int i, const glm::dvec3& val)
		{
			m_boundaryX[i] = val;
		}

		FORCE_INLINE const double& getBoundaryPsi(const unsigned int i) const
		{
			return m_boundaryPsi[i];
		}

		FORCE_INLINE double& getBoundaryPsi(const unsigned int i)
		{
			return m_boundaryPsi[i];
		}

		FORCE_INLINE void setBoundaryPsi(const unsigned int i, const double& val)
		{
			m_boundaryPsi[i] = val;
		}

		FORCE_INLINE const double& getLambda(const unsigned int i) const
		{
			return m_lambda[i];
		}

		FORCE_INLINE double& getLambda(const unsigned int i)
		{
			return m_lambda[i];
		}

		FORCE_INLINE void setLambda(const unsigned int i, const double& val)
		{
			m_lambda[i] = val;
		}

		FORCE_INLINE const double& getDensity(const unsigned int i) const
		{
			return m_density[i];
		}

		FORCE_INLINE double& getDensity(const unsigned int i)
		{
			return m_density[i];
		}

		FORCE_INLINE void setDensity(const unsigned int i, const double& val)
		{
			m_density[i] = val;
		}

		FORCE_INLINE glm::dvec3& getDeltaX(const unsigned int i)
		{
			return m_deltaX[i];
		}

		FORCE_INLINE const glm::dvec3& getDeltaX(const unsigned int i) const
		{
			return m_deltaX[i];
		}

		FORCE_INLINE void setDeltaX(const unsigned int i, const glm::dvec3& val)
		{
			m_deltaX[i] = val;
		}
	};

}


